/*
 * The MIT License
 *
 * Copyright (c) 2009 André D. Piske
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 */
package org.gohtml;

/**
 * Utils methods for text.
 *
 * @author André D. Piske
 * @since 0.1 alpha
 * @version 0.1 alpha
 */
public final class EntitiesUtil {

    // TODO: this class must be better implemented
    private static String entityCharacter[] = null;
    private static String entityNames[] = null;

    protected EntitiesUtil() {
    }

    private static void start() {
        if (entityCharacter == null) {
            String ec[] = {
                "&", "'", "¡", " ", "¢", "£", "¤", "¥", "¦", "§",
                "¨", "©", "ª", "«", "¬", "­", "®", "¯", "°", "±", "²", "³", "´",
                "µ", "¶", "·", "¸", "¹", "º", "»", "¼", "½", "¾", "¿", "×", "÷",
                "À", "Á", "Â", "Ã", "Ä", "Å", "Æ", "Ç", "È", "É", "Ê", "Ë", "Ì",
                "Í", "Î", "Ï", "Ð", "Ñ", "Ò", "Ó", "Ô", "Õ", "Ö", "Ø", "Ù", "Ú",
                "Û", "Ü", "Ý", "Þ", "ß", "à", "á", "â", "ã", "ä", "å", "æ", "ç",
                "è", "é", "ê", "ë", "ì", "í", "î", "ï", "ð", "ñ", "ò", "ó", "ô",
                "õ", "ö", "ø", "ù", "ú", "û", "ü", "ý", "þ", "ÿ"};
            int size = ec.length;
            entityCharacter = new String[size];
            System.arraycopy(ec, 0, entityCharacter, 0, size);
        }

        if (entityNames == null) {
            String en[] = {
                "amp", "apos", "iexcl", "nbsp",
                "cent", "pound", "curren", "yen", "brvbar", "sect", "uml",
                "copy", "ordf", "laquo", "not", "shy", "reg", "macr",
                "deg", "plusmn", "sup2", "sup3", "acute", "micro", "para",
                "middot", "cedil", "sup1", "ordm", "raquo", "frac14", "frac12",
                "frac34", "iquest", "times", "divide", "Agrave", "Aacute", "Acirc",
                "Atilde", "Auml", "Aring", "AElig", "Ccedil", "Egrave", "Eacute",
                "Ecirc", "Euml", "Igrave", "Iacute", "Icirc", "Iuml", "ETH",
                "Ntilde", "Ograve", "Oacute", "Ocirc", "Otilde", "Ouml", "Oslash",
                "Ugrave", "Uacute", "Ucirc", "Uuml", "Yacute", "THORN", "szlig",
                "agrave", "aacute", "acirc", "atilde", "auml", "aring", "aelig",
                "ccedil", "egrave", "eacute", "ecirc", "euml", "igrave", "iacute",
                "icirc", "iuml", "eth", "ntilde", "ograve", "oacute", "ocirc",
                "otilde", "ouml", "oslash", "ugrave", "uacute", "ucirc", "uuml",
                "yacute", "thorn", "yuml"};
            int size = en.length;
            entityNames = new String[size];
            System.arraycopy(en, 0, entityNames, 0, size);

        }
    }

    private static String findCharFromName(String name) {
        for (int j = 0; j < entityNames.length; ++j) {
            if (name.equals(entityNames[j])) {
                return entityCharacter[j];
            }
        }
        return null;
    }

    /**
     * Removes \n and \r and extra spaces & tabs.<br>
     * This should be called before {@code decode()}
     */
    public static String removeExtraSpaces(String str, boolean trim) {
        int textLength = str.length();
        StringBuilder result = new StringBuilder(textLength);
        final String spaces = "\t\r\n ";

        int p = 0;
        // trim left
        if (trim) {
            for (; p < textLength; ++p) {
                char c = str.charAt(p);
                if (-1 == spaces.indexOf(c)) {
                    break;
                }
            }
        }

        while (p < textLength) {
            char c = str.charAt(p);
            if (spaces.indexOf(c) != -1) {
                int nextWord = -1;
                for (int j = p; j < textLength; ++j) {
                    if (spaces.indexOf(str.charAt(j)) == -1) {
                        nextWord = j;
                        break;
                    }
                }
                if (nextWord == -1) {
                    if (!trim) {
                        result.append(' ');
                    }
                    break;
                }
                result.append(' ');
                p = nextWord;
            } else {
                int nextSpace = -1;
                for (int j = p; j < textLength; ++j) {
                    if (spaces.indexOf(str.charAt(j)) != -1) {
                        nextSpace = j;
                        break;
                    }
                }
                if (nextSpace == -1) {
                    result.append(str.substring(p));
                    break;
                }
                result.append(str.substring(p, nextSpace));
                p = nextSpace;
            }
        }

        return result.toString();
    }

    /**
     * Transform things like &nbsp; &aacute; in characters (like ' ', 'á')
     */
    public static String decode(String text) {
        int textLength = text.length();
        StringBuilder result = new StringBuilder(textLength);

        start();

        int p = 0;
        for (;;) {
            int e = text.indexOf('&', p);
            if (e < 0) {
                result.append(text.substring(p));
                break;
            }
            int c = text.indexOf(';', e);

            String value = null;
            if (c > e) {
                String entitieName = text.substring(e + 1, c);
                value = findCharFromName(entitieName);
                if (value == null && !entitieName.isEmpty() && entitieName.charAt(0) == '#') {
                    int number = -1;
                    try {
                        number = Integer.parseInt(entitieName.substring(1));
                    } catch (Exception ex) {
                    }
                    if (number != -1) {
                        char ch = (char) number;
                        value = ch + "";
                    }
                }
            }
            if (value != null) {
                result.append(text.substring(p, e));
                result.append(value);
                p = c + 1;
            } else {
                result.append(text.substring(p, e + 1));
                p = e + 1;
            }
        }

        return result.toString();
    }
}
